package com.pang.springcloud.controller;


import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.pang.springcloud.dao.PaymentDao;
import com.pang.springcloud.entities.CommonResult;
import com.pang.springcloud.entities.Payment;
import com.pang.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author： pang-yun
 * @date： 2022-02-08 11:03
 * Description:
 */
@RestController
@Slf4j
public class PaymentController {

    @Autowired
    private PaymentService paymentService;


    @Value("${server.port}")
    private String serverPort;

    //如果发送的JSON数据是一个类中的不同属性，在Controller方法中使用@RequestBody会直接封装进该类中
    @PostMapping("/payment/add")
    public CommonResult add(@RequestBody Payment payment) {
        int result = paymentService.add(payment);
        log.info("------result " + result);
        if (result > 0) {
            return new CommonResult(200, "插入数据成功 + serverPort: " + serverPort, result);
        } else {
            return new CommonResult(400, "插入失败");
        }
    }


    @GetMapping("/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        Payment paymentById = paymentService.getPaymentById(id);
        log.info("-----查询+ " + " s");
        if (paymentById != null) {
            return new CommonResult<Payment>(200, "查询数据成功 + serverPort: " + serverPort, paymentById);
        } else {
            return new CommonResult(400, "查询失败");
        }
    }


    @Autowired
    private PaymentDao paymentDao;

    @GetMapping("/payment/test")
    public CommonResult<Payment> getPayment() {
        Payment payment = paymentDao.getPayment(1L, "一");
        return new CommonResult<>(200, "success", payment);
    }


    //--------------------------服务发现-----

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/payment/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();
        services.stream().forEach(s -> log.info("-------name: " + s));
        return services;
    }


    @GetMapping("/payment/loadBalances")
    public String getPaymentLoadBalances() {
        return serverPort;
    }

    //进行OpenFeign 超时测试
    @GetMapping("/payment/timeout")
    public String getServerPortTimeout() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        return serverPort;
    }


    //---------------------hystrix----服务降级----------------------------------
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Long id) {
        return "线程池: " + Thread.currentThread().getName() + " paymentInfo_OK: id:  " + id;
    }


    @GetMapping("/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "handler",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
            })
    public String paymentInfo_TIMEOUT(@PathVariable("id") Long id) {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池: " + Thread.currentThread().getName() + " paymentInfo_OK: id:  " + id + " sleep : " + 3;
    }

    public String handler(@PathVariable("id") Long id) {
        return "sorry  it's too long !!!!  so we couldn't not to exit !";
    }

    // 降级使用的方法名称可以不同 ， 但是参数必须相同 否则会报错
    public String noParamHandler() {
        return "this is no params";
    }


    //-----服务熔断---

    @GetMapping("/payment/circuit/{id}")
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),  // 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失败率达到多少后跳闸
    }) // 在10秒内的窗口期内， 发送10次请求，失败率达到 60% 后失败
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        if (id < 0) {
            throw new RuntimeException("*******id 不能为负数");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "\t" + "调用成功， 流水号: " + serialNumber;
    }

    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
        return "id 不能为负数，请稍后再试， -------- id: " + id;
    }

}
